#pragma once
#include <vector>
#include "ShaderParameter.h"

//
// MaterialParameterRef
//
struct MaterialParameterRef
{
	enum EParamType
	{
		EPT_None = 0,
		EPT_Scaler,
		EPT_Vector4,
		EPT_Texture,
		EPT_Max,
	};

	EParamType ParamType;
	size_t Index;
	ShaderParameter Register;

	MaterialParameterRef() : ParamType(EPT_None) {}
	MaterialParameterRef(EParamType type, size_t index) : ParamType(type), Index(index) {}
	bool Valid() const { return ParamType > EPT_None && ParamType < EPT_Max; }
};
typedef std::vector<MaterialParameterRef> MaterialParameterRefList;

//
// UniformParam
//
template<typename T>
struct UniformParam
{
	enum { MAX_PARAM_NAME = 32 };
	char Name[MAX_PARAM_NAME];
	T Value;

	UniformParam(const std::string& name, const T& v) : Value(v) 
	{
		strcpy_s(Name, MAX_PARAM_NAME, name.c_str());
		Name[MAX_PARAM_NAME - 1] = '\0';
	}
};

typedef size_t TextureIndex;
typedef UniformParam<float> ScalerParam;
typedef UniformParam<Vector4> Vector4Param;
typedef UniformParam<TextureIndex> TextureParam;
typedef std::vector<ScalerParam> ScalerParamList;
typedef std::vector<Vector4Param> Vector4ParamList;
typedef std::vector<TextureParam> TextureParamList;

//
// MaterialParameter
//
struct MaterialParameter
{
	ScalerParamList ScalerParams;
	Vector4ParamList Vector4Params;
	TextureParamList TextureParams;

	MaterialParameterRef GetParamRef(const std::string& name) const
	{
		for (size_t i = 0; i < ScalerParams.size(); i++)
		{
			if (name == ScalerParams[i].Name)
				return MaterialParameterRef(MaterialParameterRef::EPT_Scaler, i);
		}
		
		for (size_t i = 0; i < Vector4Params.size(); i++)
		{
			if (name == Vector4Params[i].Name)
				return MaterialParameterRef(MaterialParameterRef::EPT_Vector4, i);
		}
		
		for (size_t i = 0; i < TextureParams.size(); i++)
		{
			if (name == TextureParams[i].Name)
				return MaterialParameterRef(MaterialParameterRef::EPT_Texture, i);
		}

		return MaterialParameterRef();
	}

	void Set(const MaterialParameterRef& ref, float value)
	{
		assert(ref.ParamType == MaterialParameterRef::EPT_Scaler);
		assert(ref.Index < ScalerParams.size());
		ScalerParams[ref.Index].Value = value;
	}

	void Set(const MaterialParameterRef& ref, const Vector4& value)
	{
		assert(ref.ParamType == MaterialParameterRef::EPT_Vector4);
		assert(ref.Index < Vector4Params.size());
		Vector4Params[ref.Index].Value = value;
	}

	void Set(MaterialParameterRefList& refList) const
	{
		for (MaterialParameterRefList::const_iterator it(refList.begin()), end(refList.end()); it != end; it++)
		{
			switch (it->ParamType)
			{
			case MaterialParameterRef::EPT_Scaler:
				assert(it->Index < ScalerParams.size());
				it->Register.SetPixelShaderValue(ScalerParams[it->Index].Value);
				break;
			case MaterialParameterRef::EPT_Vector4:
				assert(it->Index < Vector4Params.size());
				it->Register.SetPixelShaderValue(Vector4Params[it->Index].Value);
				break;
			case MaterialParameterRef::EPT_Texture:
				break;
			}
		}
	}
};